﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;

using Atosenet.PluginEngine;


namespace Atosenet.IO
{
    [PluginAttribute("Atosenet", "Atosenet.IO.UdpClientIO", "UDP客户端连接", PluginType.IO)]
    internal class UdpClientIO : BaseIO
    {
        #region 成员

        private Socket _udpSocket;
        private Thread _udpThread;
        private IPEndPoint _localEP, _remoteEP;

        #endregion


        #region 初始化

        public UdpClientIO()
            : base(UdpClientIOParameter.Default)
        { }

        public UdpClientIO(UdpClientIOParameter param)
            : base(param)
        { }

        #endregion


        #region 公开函数

        public override bool ApplyParameter()
        {
            try
            {
                if (IsOpened)
                    return false;

                _localEP = new IPEndPoint(IPAddress.Any, IOParam.LocalPort);
                _remoteEP = new IPEndPoint(IPAddress.Parse(IOParam.RemoteIP), IOParam.RemotePort);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public override bool Open()
        {
            try
            {
                if (IsOpened)
                    return false;

                _udpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                _udpSocket.ReceiveBufferSize = 1024 * 128;
                _udpSocket.SendBufferSize = 1024 * 128;
                _udpSocket.Bind(_localEP);
                _udpSocket.Connect(_remoteEP);

                if (_udpThread == null || _udpThread.ThreadState != System.Threading.ThreadState.Running)
                {
                    _udpThread = new Thread(new ThreadStart(ReceivingProc));
                    _udpThread.IsBackground = true;
                    _udpThread.Name = "UdpClientIO_ReceiveThread";
                    _udpThread.Start();
                }

                OnIOOpened();
                return true;
            }
            catch
            {
                if (_udpThread != null && _udpThread.IsAlive)
                    _udpThread.Abort();
                return false;
            }
        }

        public override bool Close()
        {
            try
            {
                if (!IsOpened)
                    return false;

                _udpSocket.Shutdown(SocketShutdown.Both);
                _udpSocket.Close(5);

                if (_udpThread != null && _udpThread.IsAlive)
                    _udpThread.Abort();

                OnIOClosed();
                return true;
            }
            catch
            {
                return false;
            }
        }

        public override bool Close(int id)
        {
            if (id == ID)
                return Close();

            return false;
        }

        public override int WriteTo(int id, byte[] buffer, int offset, int length)
        {
            if (id == ID)
                return Write(buffer, offset, length);

            return -1;
        }
        
        public override int Write(byte[] buffer, int offset, int length)
        {
            try
            {
                if (!IsOpened)
                    return -1;

                return _udpSocket.Send(buffer, offset, length, SocketFlags.None);
            }
            catch
            {
                return -1;
            }
        }

        #endregion


        #region 核心函数

        protected virtual void ReceivingProc()
        {
            try
            {
                while (true)
                {
                    byte[] received = new byte[1024 * 128];
                    int receivedCount = _udpSocket.Receive(received);
                    byte[] data = new byte[receivedCount];
                    Array.Copy(received, 0, data, 0, data.Length);
                    OnRawDataReceived(data);
                }
            }
            catch 
            {
                OnRawDataReceived(IOErrorType.ReadError);
            }
        }

        #endregion


        #region 属性

        public override IOModeType IOMode
        {
            get { return IOModeType.Client; }
        }

        public new UdpClientIOParameter IOParam
        {
            get { return base.IOParam as UdpClientIOParameter; }
        }

        #endregion
    }
}
